package m3f.backprojection;

import java.util.Hashtable;

import org.jblas.DoubleMatrix;

import m3f.computing.ConcurrentTemplate;
import m3f.data.MultimodalDataProvider;
import m3f.io.DenseMatrixWriter;
import m3f.matrix.Minibatch;

public class ConcurrentCombinedMatrixWriter extends ConcurrentTemplate{
	
	private MultimodalDataProvider trainingData;
	private DenseMatrixWriter writer;
	private DoubleMatrix P;
	private Hashtable<Integer, DoubleMatrix> cache;
	private int minibatchToWrite;
	private double alpha;
	
	public ConcurrentCombinedMatrixWriter(MultimodalDataProvider data, DenseMatrixWriter writer, DoubleMatrix P, double alpha){
		super(data.matrixRows()/data.getMinibatchSize() + 1);
		this.trainingData = data;
		this.writer = writer;
		this.P = P.transpose();
		this.alpha = alpha;
		
		cache = new Hashtable<Integer, DoubleMatrix>();
		minibatchToWrite = 0;
	}

	@Override
	public void singleOperation(int reg) {
		Minibatch V, H;
		synchronized(trainingData){
			V = trainingData.nextVisual();  
			H = trainingData.nextTextual();
		}
		DoubleMatrix HBP = Combiner.backprojection(V, H, P, alpha);
		cache.put(V.getId(), HBP);
		updateFile();
	}
	
	private synchronized void updateFile(){
		while(cache.keySet().contains(minibatchToWrite)){
			System.out.println("Writing minibatch " + minibatchToWrite);
			DoubleMatrix H = cache.remove(minibatchToWrite);
			writer.appendMatrix(H, true);
			minibatchToWrite++;
		}
	}

}
